package me.yuxiaoyao.lock.interceptor;

import me.yuxiaoyao.lock.expression.DistributedLockExpressionEvaluator;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.lang.Nullable;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author kerryzhang on 2020/12/22
 */

class DistributedLockOperationExpressionEvaluator extends DistributedLockExpressionEvaluator {

    /**
     * SpEL 表达式缓存
     */
    private final Map<ExpressionKey, Expression> keyCache = new ConcurrentHashMap<>(64);


    public EvaluationContext createEvaluationContext(Method method,
                                                     Object[] args,
                                                     Object target,
                                                     Class<?> targetClass,
                                                     Method targetMethod,
                                                     @Nullable BeanFactory beanFactory) {
        ExpressionRootObject rootObject = new ExpressionRootObject(method, args, target, targetClass);
        MethodBasedEvaluationContext evaluationContext = new MethodBasedEvaluationContext(rootObject, targetMethod, args, getParameterNameDiscoverer());
        if (beanFactory != null) {
            evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
        }
        return evaluationContext;
    }


    /**
     * 这里不缓存
     *
     * @param keyExpression
     * @param evalContext
     * @return
     */
    @Nullable
    public Object key(String keyExpression, EvaluationContext evalContext) {
        Expression expr = getParser().parseExpression(keyExpression);
        return expr.getValue(evalContext);
    }


    /**
     * @param keyExpression
     * @param methodKey
     * @param evalContext
     * @return
     */
    @Nullable
    public Object keyWithCache(String keyExpression, AnnotatedElementKey methodKey, EvaluationContext evalContext) {
        return getExpression(this.keyCache, methodKey, keyExpression).getValue(evalContext);
    }

    void clear() {
        this.keyCache.clear();
    }
}
